package com.bluerox.updating;

import java.io.File;
import java.util.Iterator;
import java.util.List;

import org.jdom.Document;
import org.jdom.Element;

/** 
* 下载数据文件<br><br>
* 
* Example:<br><br>
* 
* Entity entity = new Entity();<br>
* entity.setTitle("Race");<br>
* entity.setVersion("1.0.0");<br>
* entity.setBaseUrl("http://localhost:8080/");<br>
* ...<br><br>
* 
* String statusFileName = "/home/lijianbo/test/Race/temp/status/1234567890abcdef.xml";<br>
* Document statusDoc = XML.parseFile(statusFileName);<br><br>
* 
* DownloadFiles df = new DownloadFiles(entity, statusDoc);<br>
* 
* String levelFileName = "/home/lijianbo/test/Race/temp/Race_1_0_0_level_1.xml";<br>
* Document levelDoc = XML.parseFile(levelFileName);<br><br>
* Element element = levelDoc.getRootElement().getchild("root");<br>
* String path = "/home/lijianbo/test/Race/temp/race";<br>
* df.download(element, path);<br>
* 
* @author 李建波 
*/
public class DownloadFiles {
	
	private HttpService service = null;
	private Entity entity = null;
	private Document statusDoc = null;
	
	/**
	 * 构造函数
	 * @param entity 程序实体对象
	 * @param statusDoc 状态文件解析对象
	 */
	public DownloadFiles(Entity entity, Document statusDoc){
		this.entity = entity;
		this.statusDoc = statusDoc;
		service = new HttpService();
	}
	
	/**
	 * 下载节点中描述的文件
	 * 
	 * Example:<br><br>
	 * 
	 * 初始化程序实体对象
	 * Entity entity = new Entity();<br>
	 * entity.setTitle("Race");<br>
	 * entity.setVersion("1.0.0");<br>
	 * entity.setBaseUrl("http://localhost:8080/");<br>
	 * ...<br><br>
	 * 
	 * 得到状态文件的Document
	 * String statusFileName = "/home/lijianbo/test/Race/temp/status/1234567890abcdef.xml";<br>
	 * Document statusDoc = XML.parseFile(statusFileName);<br><br>
	 * 
	 * DownloadFiles df = new DownloadFiles(entity, statusDoc);<br>
	 * 
	 * String levelFileName = "/home/lijianbo/test/Race/temp/Race_1_0_0_level_1.xml";<br>
	 * Document levelDoc = XML.parseFile(levelFileName);<br><br>
	 * Element element = levelDoc.getRootElement().getchild("root");<br>
	 * String path = "/home/lijianbo/test/Race/temp/race";<br>
	 * df.download(element, path);<br>
	 * @param e XML中的树状文件结构的节点对象
	 * @param path 当前节点的基本路径
	 */
	@SuppressWarnings("unchecked")
	public void download(Element e, String path){
		List<Element> directories = e.getChildren("directory");
		List<Element> files = e.getChildren("file");
		int dirNum = directories.size();
		int fileNum = files.size();
		
		//创建当前文件夹
		System.out.println("创建路径：" +  path);
		File dir = new File(path);
		dir.mkdirs();
		
		//递归方式处理文件夹
		if(dirNum > 0){
			for(int i=0;i<dirNum;i++){
				this.download(directories.get(i), path + File.separator + directories.get(i).getAttributeValue("name"));
			}
		}
		
		//下载文件
		if(fileNum > 0){
			for(int i=0;i<fileNum;i++){
				String fileMD5 = files.get(i).getChildText("md5");
				String currMD5 = "";
				String zipFileName = "";
				
				String fileStatus = this.statusDoc.getRootElement().getChild("md5-" + fileMD5).getAttributeValue("status");
				
				if(fileStatus.equals(Entity.DOWNLOAD)){
					System.out.println(files.get(i).getAttributeValue("name") + "文件已存在，跳过。");
					continue;
				}
				//判断下载后的文件MD5是否与服务器端MD5一致，如不一致，重新下载。
				do{
					String fileName = files.get(i).getAttributeValue("name");
					zipFileName = fileName + "_" + this.entity.getVersion().replace('.', '_') + ".zip";
					System.out.println("下载文件：" + zipFileName);
					service.send(this.entity.getBaseUrl(), path, zipFileName);
					try {
						currMD5 = MD5.getHash(path + File.separator + zipFileName, "MD5");
						System.out.println("服务器文件MD5：" + fileMD5);
						System.out.println("客户端文件MD5：" + currMD5);
					} catch (Exception e1) {
						e1.printStackTrace();
					}
				}while(!fileMD5.equals(currMD5));
				
				//解压缩文件并删除压缩包
				String zipFilePath = path + File.separator + zipFileName;  
				Zip.unzipFile(path, zipFilePath);
				new File(path + File.separator + zipFileName).delete();
				
				//更新状态文件
				this.statusDoc.getRootElement().getChild("md5-" + fileMD5).setAttribute("status", "download");
				XML xml = new XML(this.entity);
				xml.save(this.statusDoc, this.entity.getTempStatusPath() + File.separator + this.entity.getStatusFileName());
			}
		}
	}
	
	/**
	 * 重写下载方法，这个方法中需要指定下载的级别，由于状态文件只有一个，所有的要下载的文件都放在该文件夹下，他们之间用的是&lt;leve value='1/2/3...'&gt;方式分开<br>
	 * 所以重写下载方法来扩充此功能。
	 * @param e XML中的树状文件结构的节点对象
	 * @param path 当前节点的基本路径
	 * @param levelValue 对应的level级别
	 */
	public void download(Element e, String path, String levelValue) {
		List<Element> directories = e.getChildren("directory");
		List<Element> files = e.getChildren("file");
		int dirNum = directories.size();
		int fileNum = files.size();
		
		//创建当前文件夹
		System.out.println("创建路径：" +  path);
		File dir = new File(path);
		dir.mkdirs();
		
		//递归方式处理文件夹
		if(dirNum > 0){
			for(int i=0;i<dirNum;i++){
				this.download(directories.get(i), path + File.separator + directories.get(i).getAttributeValue("name"),levelValue);
			}
		}
		
		//下载文件
		if(fileNum > 0){
			for(int i=0;i<fileNum;i++){
				String fileMD5 = files.get(i).getChildText("md5");
				String currMD5 = "";
				String zipFileName = "";
				//文件状态
				String fileStatus = null;
				
				//在这里需要指定对应的级别值，然后在该级别值下面操作相关的文件
				List list = this.statusDoc.getRootElement().getChildren("level");
				Iterator iter = list.iterator();
				Element element = null;
				while(iter.hasNext()) {
					element = (Element)iter.next();
					if(element.getAttributeValue("value").equals(levelValue)) {
						fileStatus = element.getChild("md5-" + fileMD5).getAttributeValue("status");
					}
				}
				
				if(fileStatus.equals(Entity.DOWNLOAD)){
					System.out.println(files.get(i).getAttributeValue("name") + "文件已存在，跳过。");
					continue;
				}
				//判断下载后的文件MD5是否与服务器端MD5一致，如不一致，重新下载。
				do{
					String fileName = files.get(i).getAttributeValue("name");
					zipFileName = fileName;
					System.out.println("下载文件：" + zipFileName);
					//在服务器端资源文件放在相应的level文件夹下
					service.send(this.entity.getBaseUrl() + "level" + levelValue + File.separator, path, zipFileName);
					try {
						currMD5 = MD5.getHash(path + File.separator + zipFileName, "MD5");
						System.out.println("服务器文件MD5：" + fileMD5);
						System.out.println("客户端文件MD5：" + currMD5);
					} catch (Exception e1) {
						e1.printStackTrace();
					}
				}while(!fileMD5.equals(currMD5));
				
				//解压缩文件并删除压缩包,边下载边解压缩
				String zipFilePath = path + File.separator + zipFileName;  
				Zip.unzipFile(path, zipFilePath);
				new File(path + File.separator + zipFileName).delete();
				
				//在这里需要指定对应的级别值，然后在该级别值下面操作相关的文件
				List list2 = this.statusDoc.getRootElement().getChildren("level");
				Iterator iter2 = list.iterator();
				Element element2 = null;
				while(iter2.hasNext()) {
					element2 = (Element)iter2.next();
					if(element2.getAttributeValue("value").equals(levelValue)) {
						element2.getChild("md5-" + fileMD5).setAttribute("status","download");
					}
				}
				XML xml = new XML(this.entity);
				xml.save(this.statusDoc, this.entity.getTempStatusPath() + File.separator + this.entity.getStatusFileName());
			}
		}
	}
 }
